﻿using System;

using System.IO;
using Microsoft.WindowsAzure.ServiceRuntime;
using NougakudoCompanion.Commons;

namespace NougakudoCompanion.Utils
{
    public class Nougakudo
    {
        string WORKING_FOLDER = null;
        string RUNTIME = null;

        System.Timers.Timer queueTimer;

        Nougakudo()
        {
            WORKING_FOLDER = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_WORKING_FOLDER);
            //RUNTIME = Path.Combine(RoleEnvironment.GetLocalResource(Constants.RESOURCE_RUNTIME).RootPath, WORKING_FOLDER);
            RUNTIME = Path.Combine(ShortcutPathUtility.GetShortcutRoot(), Constants.RESOURCE_RUNTIME, WORKING_FOLDER);
        }

        /// <summary>
        /// NougakuDoController start.
        /// 1.Create Shortcut folder as Symboloc link.
        /// 2.Set full control acl to local resource folders.
        /// 3.Copy runtime modules to local resource folder.
        /// 4.Create azure.xml as NougakuDoController environment of Windows Azure.
        /// 5.Start NougakuDoController.
        /// </summary>
        /// <returns></returns>
        public static bool Start()
        {
            try
            {
                var ret = ShortcutPathUtility.CreateNougakudoShortcut();
#if DEBUG
                Utils.Logging.Write("ShortcutPath result =" + ret.ToString());
#endif
                if (!ret) return false;

                ret = PermissionUtility.Start();
#if DEBUG
                Utils.Logging.Write("Permission result =" + ret.ToString());
#endif
                if (!ret) return false;
                ret = RuntimeCopy.Start();
#if DEBUG
                Logging.Write("Copy result =" + ret.ToString());
#endif
                if (!ret) return false;
                ret = NougakudoEnvironment.Start();
#if DEBUG
                Logging.Write("azure,xml result =" + ret.ToString());
#endif
                if (!ret) return false;
                var nougakudo = new Nougakudo();
                Logging.Write("NougakuDoController Start");
                ret = nougakudo.ControllerStart();

                // Operation message for Queue storage.
                nougakudo.queueTimer = new System.Timers.Timer();
                nougakudo.queueTimer.Interval = 1000.0 * Commons.Constants.QUEUE_INTERVAL;
                nougakudo.queueTimer.Elapsed += new System.Timers.ElapsedEventHandler(nougakudo.queueTimer_Elapsed);
                nougakudo.queueTimer.Start();

                return ret;
            }
            catch (Exception e)
            {
                Logging.Write("Error:" + e.Message);
                return false;
            }

        }

        /// <summary>
        /// Check operation from queue storage. Then create a operation file for BougakuDoController.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void queueTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var instance = RoleEnvironment.CurrentRoleInstance.Id;
            var ops = QueueStorageHelper.GetMessageCount(instance);
            if (!ops.Item1)
            {
                Logging.Write("NougakuDoController receive error from Queue (" + ops.Item2 + ")");
                return;
            }
            if (ops.Item3 == 0) return;
            Logging.Write("NougakuDoController operation start from Queue message.");
            for (var i = 0; i < ops.Item3; i++)
            {
                var messageResult = QueueStorageHelper.GetMessage(instance);
                if (!messageResult.Item1)
                {
                    Logging.Write("NougakuDoController receive error from Message (" + messageResult.Item2 + ")");
                    return;
                }
                var opsData = QueueStorageHelper.GetData(messageResult.Item3);
#if DEBUG
                Logging.Write("NougakuDoController operation = " + opsData.Item1 + " from Message");
#endif
                var ret = OutputOperation(opsData.Item1, opsData.Item2);
                if (!ret.Item1)
                {
                    Logging.Write("NougakuDoController operation error from Message (" + ret.Item2 + ")");
                    return;
                }
            }
            Logging.Write("NougakuDoController operation terminate from Queue message.");
        }

        /// <summary>
        /// Create operation file.
        /// </summary>
        /// <param name="file">Operation a file name</param>
        /// <param name="applications"></param>
        /// <returns></returns>
        static Tuple<bool, string> OutputOperation(string file, string[] applications)
        {
            file = Path.Combine(NougakudoEnvironment.RuntimeFolder, file);
#if DEBUG
            Logging.Write("Write ope = " + file);
#endif
            try
            {
                if (System.IO.File.Exists(file))
                    System.IO.File.Delete(file);
                System.IO.File.WriteAllLines(file, applications);
                return new Tuple<bool, string>(true, "");
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Stop NougakuDoController.
        /// </summary>
        /// <returns></returns>
        public static bool Stop()
        {
            var nougakudo = new Nougakudo();
            Logging.Write("NougakuDoController Stop");
            return nougakudo.ControllerStop();
        }

        /// <summary>
        /// Start a NougakuDoController as another process.
        /// </summary>
        /// <returns></returns>
        bool ControllerStart()
        {
            try
            {
                var exe = Path.Combine(RUNTIME, Constants.NOUGAKUGO_CONTRALLER);
                System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo(exe);
                procInfo.WorkingDirectory = RUNTIME;
                System.Diagnostics.Process.Start(procInfo);
                return true;
            }
            catch (Exception e)
            {
                Logging.Write("Start error = " + e.Message);
                return false;
            }
        }

        /// <summary>
        /// Create a role stop request to NougakuDoController.
        /// </summary>
        /// <returns></returns>
        bool ControllerStop()
        {

            var stop = Path.Combine(RUNTIME, Constants.STOP_REQUEST);
            try
            {
                if (File.Exists(stop))
                    File.Delete(stop);
                using (var stoprequest = File.Create(stop))
                {
                    // Create a zero size file.
                }
#if DEBUG
                Logging.Write("Stop request created = " + stop);
#endif

            }
            catch (Exception e)
            {
                Logging.Write("Stop error = " + e.Message);
                return false;
            }
            return true;
        }

    }
}